package com.guangfeng.yql.comm.netty.initalizer;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.guangfeng.yql.comm.netty.NettyProperty;
import com.guangfeng.yql.comm.netty.verify.DataVerify;
import io.netty.channel.*;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.http.*;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.codec.http.websocketx.extensions.compression.WebSocketServerCompressionHandler;
import io.netty.handler.stream.ChunkedWriteHandler;
import org.springframework.stereotype.Component;

import java.util.List;

@Component
public class MessageInitializer extends BaseInitializer<SocketChannel> {


    @Override
    public void init(NettyProperty nettyProperty) {
        setNettyProperty(nettyProperty);
    }

    /**
     * This method will be called once the {@link Channel} was registered. After the method returns this instance
     * will be removed from the {@link ChannelPipeline} of the {@link Channel}.
     *
     * @param socketChannel the {@link Channel} which was registered.
     * @throws Exception is thrown if an error occurs. In that case it will be handled by
     *                   {@link #exceptionCaught(ChannelHandlerContext, Throwable)} which will by default close
     *                   the {@link Channel}.
     */
    @Override
    protected void initChannel(SocketChannel socketChannel) throws Exception {
        ChannelPipeline pipeline = socketChannel.pipeline();
        pipeline.addLast("httpServerCodec", new HttpServerCodec());
        pipeline.addLast("chunkedWriteHandler", new ChunkedWriteHandler());
        pipeline.addLast("httpObjectAggregator", new HttpObjectAggregator(getNettyProperty().getMaxContentLength()));
        pipeline.addLast("webSocketServerCompressionHandler", new WebSocketServerCompressionHandler());
        pipeline.addLast("webSocketServerProtocolHandler", new WebSocketServerProtocolHandler(getNettyProperty().getPath(), null, true, getNettyProperty().getMaxFrameSize()));
        pipeline.addLast("channelInboundHandlerAdapterImpl", new ChannelInboundHandlerAdapter() {
            @Override
            public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
                if (msg instanceof FullHttpRequest) {
                    FullHttpRequest request = (FullHttpRequest) msg;
                    String uri = request.uri();
                    if (!uri.equals(getNettyProperty().getPath())) {
                        ctx.channel().writeAndFlush(new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.NOT_FOUND)).addListener(ChannelFutureListener.CLOSE);
                        return;
                    }
                }
                List<Class<? extends DataVerify>> list = getNettyProperty().getVerify();
                if (CollUtil.isNotEmpty(list)) {
                    for (Class<? extends DataVerify> aClass : list) {
                        DataVerify verify = SpringUtil.getBean(aClass);
                        if (!verify.verify(ctx, msg)) {
                            return;
                        }
                    }
                }
                super.channelRead(ctx, msg);
            }
        });
        pipeline.addLast(getNettyProperty().getHandler().getName(), SpringUtil.getBean(getNettyProperty().getHandler()));
    }


}
